from fastapi import APIRouter, Body, Path, Query, Depends
from backend.db.neo4j_driver import neo4j_driver
from backend.utils.logger import logger
from backend.utils.response_filter import filter_sensitive_fields
from backend.schemas.equipment import EquipmentCreate, EquipmentUpdate, EquipmentDetail
from backend.auth.auth import get_current_user
from datetime import datetime
from typing import Optional
from backend.utils.consts import SERVER_INTERNAL_ERROR_MSG, EQUIPMENT_NOT_FOUND_MSG
from backend.cypher_defs.cypher_equipment import (
    MATCH_EQUIPMENT_BY_ID,
    GET_EQUIPMENT_TYPE_TREE,
    GET_EQUIPMENT_LIST,
    CREATE_EQUIPMENT,
    CREATE_EQUIPMENT_BENCH_REL,
    CREATE_EQUIPMENT_TYPE_REL,
    DELETE_EQUIPMENT,
    CHECK_EQUIPMENT_EXISTS,
    UPDATE_EQUIPMENT
)
from backend.utils.model_utils import fill_create_update_fields, fill_update_fields

router = APIRouter(prefix="/api/equipments", tags=["equipment"])

def build_type_tree(types):
    for t in types:
        t['children'] = []
    tree = []
    id_map = {t['equipmentTypeId']: t for t in types}
    type_has_child = set(t['parentId'] for t in types if t['parentId'])
    for t in types:
        if t['parentId']:
            parent = id_map.get(t['parentId'])
            if parent:
                parent['children'].append(t)
        else:
            tree.append(t)
    return tree, type_has_child

def attach_equipments_to_types(types, equipments, id_map, type_has_child):
    for t in types:
        if t['equipmentTypeId'] not in type_has_child:
            t['children'] = [
                {
                    "equipmentId": e["equipmentId"],
                    "equipmentName": e["equipmentName"],
                    "icon": t.get("icon"),
                    "modelUrl": t.get("modelUrl"),
                    "status": e.get("status")
                }
                for e in equipments if e["equipmentTypeId"] == t["equipmentTypeId"]
            ]

def convert_is_must(types):
    for t in types:
        t['isMust'] = str(t.get('isMust')).lower() == 'true'

@router.get(
    "/",
    response_model=dict,
    summary="获取设备列表",
    description="支持按设备名称或编号模糊查询，返回所有设备信息及类型树状结构，类型叶子节点为设备，设备icon和modelUrl继承类型。"
)
async def get_equipment_list(keyword: Optional[str] = Query(None, description="设备名称或编号")):
    try:
        # 查询所有设备类型
        result = neo4j_driver.query(GET_EQUIPMENT_TYPE_TREE)
        types = [dict(r) for r in result]
        tree, type_has_child = build_type_tree(types)

        # 查询所有设备
        where = "WHERE e.equipmentName CONTAINS $keyword OR e.equipmentId CONTAINS $keyword" if keyword else ""
        params = {"keyword": keyword} if keyword else {}
        cypher = GET_EQUIPMENT_LIST.format(where=where)
        result = neo4j_driver.query(cypher, params)
        equipments = [dict(r["e"], equipmentTypeId=r.get("equipmentTypeId")) for r in result]
        equipments = filter_sensitive_fields(equipments)

        # 组装类型树，叶子节点为设备
        convert_is_must(types)
        attach_equipments_to_types(types, equipments, id_map, type_has_child)

        return {"code": 0, "msg": "success", "data": {"equipmentTypes": tree}}
    except Exception as e:
        logger.error(f"Error in get_equipment_list: {e}", exc_info=True)
        return {"code": 500, "msg": SERVER_INTERNAL_ERROR_MSG, "data": None}

@router.get(
    "/{equipmentId}",
    response_model=dict,
    summary="获取设备详情",
    description="根据设备ID获取设备的详细信息。"
)
async def get_equipment_detail(equipmentId: str = Path(...)):
    try:
        cypher = MATCH_EQUIPMENT_BY_ID
        result = neo4j_driver.query(cypher, {"equipmentId": equipmentId})
        if not result:
            return {"code": 1013, "msg": EQUIPMENT_NOT_FOUND_MSG, "data": None}
        equipment = result[0]["e"]
        return {"code": 0, "msg": "success", "data": equipment}
    except Exception as e:
        logger.error(f"Error in get_equipment_detail: {e}", exc_info=True)
        return {"code": 500, "msg": SERVER_INTERNAL_ERROR_MSG, "data": None}

@router.post(
    "/",
    response_model=dict,
    summary="创建设备",
    description="创建新的设备节点，设备ID不可重复。"
)
async def create_equipment(
    body: EquipmentCreate,
    benchId: Optional[str] = Query(None, description="所属工台ID，可选"),
    equipmentTypeId: Optional[str] = Query(None, description="设备类型ID，可选"),
    current_user: str = Depends(get_current_user)
):
    try:
        cypher = CHECK_EQUIPMENT_EXISTS
        if neo4j_driver.query(cypher, {"equipmentId": body.equipmentId}):
            return {"code": 1011, "msg": "设备ID已存在", "data": None}
        params = body.dict()
        params = fill_create_update_fields(params, current_user)
        cypher = CREATE_EQUIPMENT
        result = neo4j_driver.query(cypher, params)
        equipment = result[0]["e"] if result else None
        # 自动建立与工台的关系
        if benchId:
            cypher = CREATE_EQUIPMENT_BENCH_REL
            neo4j_driver.query(cypher, {"benchId": benchId, "equipmentId": body.equipmentId})
        # 自动建立与设备类型的关系
        if equipmentTypeId:
            cypher = CREATE_EQUIPMENT_TYPE_REL
            neo4j_driver.query(cypher, {"equipmentTypeId": equipmentTypeId, "equipmentId": body.equipmentId})
        return {"code": 0, "msg": "success", "data": equipment}
    except Exception as e:
        logger.error(f"Error in create_equipment: {e}", exc_info=True)
        return {"code": 500, "msg": SERVER_INTERNAL_ERROR_MSG, "data": None}

@router.put(
    "/{equipmentId}",
    response_model=dict,
    summary="更新设备信息",
    description="根据设备ID更新设备基本信息。"
)
async def update_equipment(
    equipmentId: str = Path(...),
    body: EquipmentUpdate = Body(...),
    current_user: str = Depends(get_current_user)
):
    try:
        cypher = MATCH_EQUIPMENT_BY_ID
        if not neo4j_driver.query(cypher, {"equipmentId": equipmentId}):
            return {"code": 1013, "msg": EQUIPMENT_NOT_FOUND_MSG, "data": None}
        set_clauses = []
        params = {"equipmentId": equipmentId}
        for k, v in body.dict(exclude_unset=True).items():
            set_clauses.append(f"e.{k} = ${{k}}")
            params[k] = v
        params = fill_update_fields(params, current_user)
        set_clauses.append("e.updatedBy = $updatedBy")
        set_clauses.append("e.updatedAt = $updatedAt")
        if set_clauses:
            cypher = UPDATE_EQUIPMENT.replace('{set_clauses}', ', '.join(set_clauses))
            result = neo4j_driver.query(cypher, params)
            equipment = result[0]["e"] if result else None
        else:
            equipment = None
        return {"code": 0, "msg": "success", "data": equipment}
    except Exception as e:
        logger.error(f"Error in update_equipment: {e}", exc_info=True)
        return {"code": 500, "msg": SERVER_INTERNAL_ERROR_MSG, "data": None}

@router.delete(
    "/{equipmentId}",
    response_model=dict,
    summary="删除设备",
    description="根据设备ID删除设备节点及其所有关联关系。"
)
async def delete_equipment(equipmentId: str = Path(...)):
    try:
        cypher = MATCH_EQUIPMENT_BY_ID
        if not neo4j_driver.query(cypher, {"equipmentId": equipmentId}):
            return {"code": 1013, "msg": EQUIPMENT_NOT_FOUND_MSG, "data": None}
        cypher = DELETE_EQUIPMENT
        neo4j_driver.query(cypher, {"equipmentId": equipmentId})
        return {"code": 0, "msg": "success", "data": None}
    except Exception as e:
        logger.error(f"Error in delete_equipment: {e}", exc_info=True)
        return {"code": 500, "msg": SERVER_INTERNAL_ERROR_MSG, "data": None} 